﻿using System;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xml.Linq;
using AzukiMap.Tools;
using AzukiMap.Tools.Logger;

namespace AzukiMap.Renderer
{
    public class VectorStyle : IVectorStyle
    {
        Brush _fill;
        FillRule _fillRule ;
        double _opacity ;
        Brush _opacityMask ;
        Brush _stroke ;
        double _strokeThickness ;
        DoubleCollection _strokeDashArray ;
        double _strokeDashOffset ;
        PenLineCap _strokeDashCap ;
        PenLineCap _strokeStartLineCap ;
        PenLineCap _strokeEndLineCap ;
        PenLineJoin _strokeLineJoin ;
        double _strokeMiterLimit ;
        double _pointWidth;
        double _pointHeight;

        PointDrawingType _pointType ;
        Image _pointImage ;
        double _adjustX;
        double _adjustY;

        XmlCommon _xmlCommon;

        public VectorStyle()
        {
            _fill = null;
            _fillRule = FillRule.EvenOdd;
            _opacity = 1.0;
            _opacityMask = null;
            _stroke = new SolidColorBrush(Colors.Black);
            _strokeThickness = 1.0;
            _strokeDashArray = new DoubleCollection();
            _strokeDashArray.Add(1);
            _strokeDashArray.Add(1);

            _strokeDashOffset = 0.0;
            _strokeDashCap = PenLineCap.Flat;
            _strokeStartLineCap = PenLineCap.Flat;
            _strokeEndLineCap = PenLineCap.Square;
            _strokeLineJoin = PenLineJoin.Round;
            _strokeMiterLimit = 1.0;
            _pointWidth = 5.0;
            _pointHeight = 5.0;
            _pointType = PointDrawingType.Circle;
            _pointImage = new Image();

            _xmlCommon = new XmlCommon();
        }

        #region IVectorStyle Members

        public Brush FillBrush
        {
            get { return _fill; }
            set { _fill = value; }
        }

        public FillRule FillRule
        {
            get { return _fillRule; }
            set { _fillRule = value; }
        }

        public double Opacity
        {
            get { return _opacity; }
            set
            {
                if (value < 0)
                {
                    Logger.Error("Opacity value should be >= 0.");
                    throw new ArgumentException("Opacity value should be >= 0.");
                }
                _opacity = value;
            }
        }

        public Brush OpacityMask
        {
            get { return _opacityMask; }
            set
            {
                _opacityMask = value;
            }
        }

        public Brush StrokeBrush
        {
            get { return _stroke; }
            set
            {
                _stroke = value;
            }
        }

        public double StrokeThickness
        {
            get { return _strokeThickness; }
            set
            {
                if (value < 0)
                {
                    Logger.Error("StrokeThickness value should be >= 0");
                    throw new ArgumentOutOfRangeException("StrokeThickness value should be >= 0");
                }
                _strokeThickness = value;
            }
        }

        public DoubleCollection StrokeDashArray
        {
            get { return _strokeDashArray; }
            set { _strokeDashArray = value; }
        }

        public double StrokeDashOffset
        {
            get { return _strokeDashOffset; }
            set { _strokeDashOffset = value; }
        }

        public PenLineCap StrokeDashCap
        {
            get { return _strokeDashCap; }
            set { _strokeDashCap = value; }
        }

        public PenLineCap StrokeStartLineCap
        {
            get { return _strokeStartLineCap; }
            set { _strokeStartLineCap = value; }
        }

        public PenLineCap StrokeEndLineCap
        {
            get { return _strokeEndLineCap; }
            set { _strokeEndLineCap = value; }
        }

        public PenLineJoin StrokeLineJoin
        {
            get { return _strokeLineJoin; }
            set { _strokeLineJoin = value; }
        }

        public double StrokeMiterLimit
        {
            get { return _strokeMiterLimit; }
            set { _strokeMiterLimit = value; }
        }

        public double PointWidth
        {
            get { return _pointWidth; }
            set
            {
                if (value < 0)
                {
                    Logger.Error("PointSize value should be >= 0.");
                    throw new ArgumentOutOfRangeException("PointSize value should be >= 0.");
                }
                _pointWidth = value;
            }
        }

        public double PointHeight
        {
            get { return _pointHeight; }
            set
            {
                if (value < 0)
                {
                    Logger.Error("PointSize value should be >= 0.");
                    throw new ArgumentOutOfRangeException("PointSize value should be >= 0.");
                }
                _pointHeight = value;
            }
        }

        public PointDrawingType PointType
        {
            get { return _pointType; }
            set { _pointType = value; }
        }

        public Image PointImage
        {
            get { return _pointImage; }
            set { _pointImage = value; }
        }

        public double AdjustX
        {
            get { return _adjustX; }
            set { _adjustX = value; }
        }

        public double AdjustY
        {
            get { return _adjustY; }
            set { _adjustY = value; }
        }

        public XElement ToXml(string elementName)
        {
            XElement vectorStyle = new XElement(elementName,
                    _xmlCommon.BrushToXml("Fill", _fill),
                    _xmlCommon.CreateElement("FillRule", _fillRule),
                    _xmlCommon.CreateElement("Opacity", _opacity),
                    _xmlCommon.BrushToXml("OpacityMask", _opacityMask),
                    _xmlCommon.BrushToXml("Stroke", _stroke),
                    _xmlCommon.CreateElement("StrokeThickness", _strokeThickness),
                    _xmlCommon.DoubleCollectionToXml("StrokeDashArray", _strokeDashArray),
                    _xmlCommon.CreateElement("StrokeDashOffset", _strokeDashOffset),
                    _xmlCommon.CreateElement("StrokeDashCap", _strokeDashCap),
                    _xmlCommon.CreateElement("StrokeStartLineCap", _strokeStartLineCap),
                    _xmlCommon.CreateElement("StrokeEndLineCap", _strokeEndLineCap),
                    _xmlCommon.CreateElement("StrokeLineJoin", _strokeLineJoin),
                    _xmlCommon.CreateElement("StrokeMiterLimit", _strokeMiterLimit),
                    _xmlCommon.CreateElement("PointWidth", _pointWidth),
                    _xmlCommon.CreateElement("PointHeight", _pointHeight),
                    _xmlCommon.CreateElement("PointType", _pointType),
                    _xmlCommon.ImageToXml("PointImage", _pointImage),
                    _xmlCommon.CreateElement("AdjustX", _adjustX),
                    _xmlCommon.CreateElement("AdjustY", _adjustY)
                    );
            return vectorStyle;
        }

        public XElement ToXml()
        {
            return ToXml("VectorStyle") ;
        }

        public void Parse(XElement styleElement)
        {
            _fill = _xmlCommon.GetBrushElement(styleElement.Element("Fill"));
            _fillRule = 
                (FillRule)_xmlCommon.GetEnumElement(styleElement, "FillRule", typeof(FillRule));
            _opacity = _xmlCommon.GetDoubleElement(styleElement, "Opacity");
            _opacityMask = _xmlCommon.GetBrushElement(styleElement.Element("OpacityMask"));
            _stroke = _xmlCommon.GetBrushElement(styleElement.Element("Stroke"));
            _strokeThickness = _xmlCommon.GetDoubleElement(styleElement, "StrokeThickness");
            _strokeDashArray = _xmlCommon.GetDoubleCollection(styleElement, "StrokeDashArray");
            _strokeDashOffset = _xmlCommon.GetDoubleElement(styleElement, "StrokeDashOffset");
            _strokeDashCap = 
                (PenLineCap)_xmlCommon.GetEnumElement(styleElement, "StrokeDashCap", typeof(PenLineCap));

            _strokeStartLineCap =
                (PenLineCap)_xmlCommon.GetEnumElement(styleElement, "StrokeStartLineCap", typeof(PenLineCap));
            _strokeEndLineCap =
                (PenLineCap)_xmlCommon.GetEnumElement(styleElement, "StrokeEndLineCap", typeof(PenLineCap));
            _strokeLineJoin =
                (PenLineJoin)_xmlCommon.GetEnumElement(styleElement, "StrokeLineJoin", typeof(PenLineJoin));
            _strokeMiterLimit = _xmlCommon.GetDoubleElement(styleElement, "StrokeMiterLimit");
            _pointWidth = _xmlCommon.GetDoubleElement(styleElement, "PointWidth");
            _pointHeight = _xmlCommon.GetDoubleElement(styleElement, "PointHeight");
            _pointType =
                (PointDrawingType)_xmlCommon.GetEnumElement(styleElement, "PointType", typeof(PointDrawingType));
            _pointImage = _xmlCommon.GetImageElement(styleElement, "PointImage");
            _adjustX = _xmlCommon.GetDoubleElement(styleElement, "AdjustX");
            _adjustY = _xmlCommon.GetDoubleElement(styleElement, "AdjustY");
        }

        #endregion
    }
}
